#include "stdafx.h"
#include "Project.h"
#include "LitPhysicsManager.h"

Project::Project( const std::string &proj_name, QWidget * w, PreviewPtr preview, PropertiesPtr props, Lit::ResourcesListPtr res )
	: QTreeWidget( w )
	, Lit::MovableListener(Lit::MT_ENTITY)
{
	mResources = res;
	mStructure = new ProjectStructure();
	mState = new ProjectSaveState();
	mPreview = preview;
	mProperties = props;

	setDragEnabled (true);  
	setDropIndicatorShown (true);  
	setDragDropMode(QAbstractItemView::DragDrop);  
	setAcceptDrops(true);  
	setDefaultDropAction( Qt::MoveAction );
	create(proj_name);
	w->layout()->addWidget( this );
	header()->setVisible( false );
}
Project::Project( QWidget * w, PreviewPtr preview, PropertiesPtr props, Lit::ResourcesListPtr res )
	: QTreeWidget( w )
	, Lit::MovableListener(Lit::MT_ENTITY)
{
	mResources = res;
	mStructure = new ProjectStructure();
	mState = new ProjectSaveState();
	mPreview = preview;
	mProperties = props;

	setDragEnabled (true);  
	setDropIndicatorShown (true);  
	setDragDropMode(QAbstractItemView::DragDrop);  
	setAcceptDrops(true);  
	setDefaultDropAction( Qt::MoveAction );
	createByUserChoice();
	w->layout()->addWidget( this );
	header()->setVisible( false );
}
Project::Project( const Project& rk )
	: mStructure( rk.mStructure )
	, mResources( rk.mResources )
	, mName( rk.mName )
	, mState( rk.mState )
	, mPreview( rk.mPreview )
	, mProperties( rk.mProperties )
{
}
Project::~Project()
{
	mState.destroy();
	mStructure.destroy();
}
void Project::exportSceneAttribs( TiXmlElement * node )
{
	if( !node ) return;

	Lit::Color amb = Lit::Root::SceneManager()->_sceneManager()->getAmbientLight();
	Ogre::ShadowTechnique shadTyp = Lit::Root::SceneManager()->_sceneManager()->getShadowTechnique();
	Lit::Color shadCol = Lit::Root::SceneManager()->_sceneManager()->getShadowColour();

	node->SetAttribute( "AmbientLighting", Ogre::StringConverter::toString(amb).c_str() );
	node->SetAttribute( "ShadowTechnique", Lit::trShadowTechnique( shadTyp ).c_str() );
	node->SetAttribute( "ShadowColor", Ogre::StringConverter::toString(shadCol).c_str() );
}

void Project::save( )
{
	std::string path;
	if( mState->isPathDefined() )
		path = mState->savePath();
	else{
		path = QFileDialog::getSaveFileName(this, "Save Scene", EDITOR_DEFAULT_PROJECT_PATH.c_str(), "Scene Project (*.sceneproj);;").toAscii().data();
		if( path.empty() )
			return;
	}

	TiXmlDocument doc;
	doc.LinkEndChild( new TiXmlDeclaration( PROJECT_VERSION_STRING, "UTF-8", "yes" ) );

	TiXmlElement * projectNode = new TiXmlElement("scene");
	exportSceneAttribs( projectNode );

	for( auto i=mStructure->nodes().begin();
		i!=mStructure->nodes().end();
		i++ )
	{
		if( i->second && i->second->movable() )
		{
			TiXmlElement * elem = new TiXmlElement("movable");
			i->second->movable()->exportAttribs( elem );
			projectNode->LinkEndChild( elem );
		}
	}
	doc.LinkEndChild( projectNode );

	doc.SaveFile(path.c_str());
	
	mState->setSaved( true, path );
}
void Project::close( )
{
	if( mState->isModified() )
	{
		int ans = QMessageBox::question( this, "Save Scene", "The scene has been modified, do you want to save changes or discard them ?", QMessageBox::Yes, QMessageBox::No );
		if( ans == QMessageBox::Yes ) save();
		mState->setModified( false );
	}
	mStructure->destroyNodes();
	Lit::Root::SceneManager()->clearScene();
	Lit::Root::PhysicsManager()->clearWorlds();
}
void Project::open( )
{
	close();
	std::string path = QFileDialog::getOpenFileName( this, "Load Scene", EDITOR_DEFAULT_PROJECT_PATH.c_str(), "Scene Project (*.sceneproj);;" ).toAscii().data();
	if( path.empty() ) return;
	mName = Ogre::StringUtil::replaceAll( Lit::FileSystem::fileName( path ), ".sceneproj", "" );
	mStructure->setup( mName, this );
	mState->setSaved( true, path );
}
void Project::create( const std::string &proj_name )
{
	mName = proj_name;
	mStructure->setup( proj_name, this );

	connect( (QTreeWidget*)this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(previewMeshChangeRequest(QTreeWidgetItem*,QTreeWidgetItem*)) );
}
void Project::createByUserChoice( )
{
	ProjectCreatorDialog *dlg = new ProjectCreatorDialog(this);
	if( dlg->exec() == QDialog::Rejected ) return;
	create(dlg->projectName());
	delete dlg, dlg = NULL;
}

QIcon Project::itemTypeIcon( ProjectItemType type ) const
{
	switch( type )
	{
		case PIT_FOLDER: return QIcon(QT_ITEM_TYPES_PATH+"FolderClosed.png");
		case PIT_ASSET: return QIcon(QT_ITEM_TYPES_PATH+"asset.png");
		case PIT_SHARED_ASSET: return QIcon(QT_ITEM_TYPES_PATH+"asset.png");
		case PIT_SCENE_NODE: return QIcon(QT_ITEM_TYPES_PATH+"unknown.png");
		case PIT_ENTITY: return QIcon(QT_ITEM_TYPES_PATH+"getEntity.png");
		case PIT_SOUND: return QIcon(QT_ITEM_TYPES_PATH+"sound.png");
		case PIT_LIGHT: return QIcon(QT_ITEM_TYPES_PATH+"light.png");
		case PIT_ROOT_NODE: return QIcon(QT_ITEM_TYPES_PATH+"world.png");

		case PIT_NONE:
		default:
			return QIcon(QT_ITEM_TYPES_PATH+"unknown.png");
	}
}
bool Project::moveObject( Lit::Movable* mov, const Lit::Vec3 &position ){
	if( mov->hasData( "LightBuddy" ) )
	{
		Lit::LightPtr l( Lit::Root::SceneManager()->getLight( mov->getData<std::string>( "LightBuddy", std::string() ) ) );
		l->setPosition( mov->getPosition() );
	}
	return true; 
}
bool Project::scaleObject( Lit::Movable* mov, const Lit::Vec3 &scale ){ return true; }
bool Project::orientObject( Lit::Movable* mov, const Ogre::Quaternion &orientation ){ return true; }

Project::NodePtr Project::createMovable( const std::string &basename, ProjectNodeType type ){
	Lit::SceneManagerPtr mgr = Lit::Root::Instance().component<Lit::SceneManager>( Lit::COM_SCENEMANAGER );
	Lit::MovablePtr ptr;
	NodePtr par = mStructure->rootNode();
	switch( type )
	{
		case PNT_ENTITY:
		{
			ptr = *mgr->createEntity( mgr->nextEntityName( basename ), basename );
			par = mStructure->entitiesNode();
			ptr->movable()->setQueryFlags( UQF_SELECTABLE );
			((Lit::Entity*)*ptr)->getEntity()->setCastShadows( true );
			break;
		}
		case PNT_LIGHT:
		{
			ptr = *mgr->createLight( mgr->nextLightName( basename ) );
			par = mStructure->lightsNode();
			Lit::LightPtr l((Lit::Light*)*ptr);
			Lit::EntityPtr ent(mgr->createEntity(ptr->getName()+"_mesh", "cube.mesh" ));

			Lit::Vec3 scale( 0.1f );
			ent->setScale( scale );

			ent->getEntity()->setQueryFlags( UQF_SELECTABLE );

			ent->getEntity()->setCastShadows( false );
			l->light()->setCastShadows( true );

			ent->setMaterialName( "Editor/Light" );

			ent->setData( "LightBuddy", l->getName() );
			l->setData( "EntityBuddy", ent->getName() );

			std::string tname;
			if( tname == Lit::trLightType( Lit::LT_POINT ) ) l->setType(Lit::LT_POINT);
			else if( tname == Lit::trLightType( Lit::LT_DIRECTIONAL ) ) l->setType(Lit::LT_DIRECTIONAL);		
			else if( tname == Lit::trLightType( Lit::LT_SPOTLIGHT ) ) l->setType(Lit::LT_SPOTLIGHT);

			ent->addListener( this );
			break;
		}
		case PNT_SOUND:
		case PNT_UNKNOWN:
		default:
			throw Lit::ImplementationMissing("Project::createMovable("+std::string(trProjectNodeType(type))+")",EXC_LOC);
	}
	return mStructure->createNode( ptr->getName(), type, ptr, par );
}
void Project::destroyNode( NodePtr node ){
	mStructure->destroyNode( node->item() );
}

/******************
*******************
****
****	SLOTS
****
*******************/

Project::NodePtr Project::findNode( const std::string &name )
{
	return mStructure->findNode( mStructure->fromItemName(name) );
}
Project::NodePtr Project::findNode( Lit::MovablePtr mov )
{
	return mStructure->findNode( mStructure->fromMovable(mov) );
}
Project::NodePtr Project::findNode( ProjectNode::ItemPtr item )
{
	return mStructure->findNode( item );
}

const Lit::ResourcesListPtr& Project::resources() const{
	return mResources;
}
Lit::ResourcesListPtr Project::resources(){
	return mResources;
}

void Project::mouseReleaseEvent( QMouseEvent * evt ){
	if( evt->button() == Qt::RightButton )
	{
		try
		{
			QTreeWidgetItem * sel = currentItem();
			QMenu * menu = new QMenu(this);
			NodePtr n = mStructure->findNode(sel);
			if( n ){
				QAction * rem = NULL;
				if( n->movable() ) rem=menu->addAction("Remove "+QString( n->getName().c_str() ));
				else{ rem=menu->addAction("Remove "+QString( n->getName().c_str() )); rem->setEnabled( false ); }
				
				if( menu->exec( QCursor::pos() ) == rem )
				{
					Lit::Root::SceneManager()->clearSelection();
					mStructure->destroyNode( sel );
				}
			}
		}
				
		catch( std::exception & e )
		{
			QMessageBox::information( this, "Error", e.what() );
		}
		catch( ... )
		{
			QMessageBox::information( this, "Error", "Unknown" );
		}
		return;
	}
	QTreeWidget::mouseReleaseEvent( evt );
}
void Project::infosUpdateRequest( QTreeWidgetItem * item ){}
void Project::previewMeshChangeRequest( QTreeWidgetItem * cur, QTreeWidgetItem * prev ){
	std::string scur = cur->text(0).toAscii().data();
	ProjectNodePtr node = mStructure->findNode( cur );
	Lit::SceneManagerPtr mgr = Lit::Root::SceneManager();
	mgr->clearSelection();
	Lit::MovablePtr mov = node->movable();
	if( node )
	{
		mProperties->updateProperties( node );
		switch( node->type() )
		{
		case PNT_ENTITY:
			mPreview->replaceMesh( mgr->getEntity( node->getName() )->getMeshName() );
			mgr->setSelected( *mgr->getEntity( node->getName() ), true );
			break;
		};
	}
}